﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Collections.TreeCollections;
using FeatureModelCore.FMInterface;
using System.Xml.Linq;
using FeatureModelCore.FMShapes;
using Collections;
using FeatureModel.Collections.TreeArgs;
using FeatureModelCore.FeatureModelEventArgs;
using FeatureModelCore.FMCrossTreeConstraint;

namespace FeatureModelCore
{
    public class FeatureTreeNode : TreeNode, IFeature, IFeatureModelObject, IFeatureTreeObject
    {
        private readonly static int _DEFAULT_WIDTH = 80;
        private readonly static int _DEFAULT_HEIGHT = 90;

        #region XML Symbol
        public readonly static string _XML_NODE_NAME = "NodeName";
        public readonly static string _XML_ANNOTATION = "Annotation";
        #endregion

        #region Properties
        public string FeatureName
        {
            get { return _featureName; }
            set
            {
                string info = string.Format("Change name from '{0}' to '{1}'"
                    , _featureName
                    , value);
                FeatureNameChangedEventArgs e = new FeatureNameChangedEventArgs(
                    this, info, 0, this._featureName, value);

                FeatureModelTree fmTree = (FeatureModelTree)this.TreeOwner;

                fmTree.PreProcess(this, e); 
                _featureName = value;
                fmTree.ProProcess(this, e);
            }
        }
        public string Annotation { get { return _annotation; } set { _annotation = value; } }
        public FeatureNodeProperty[] Properties { get { return allProperties(); } }
        public IFeature[] ChildrenNodes { get { return childrenNodes(); } }
        public IRelation[] ChildrenGroupRelationshipes { get { return childrenGroupRelationship(); } }

        public IFeature ParentNode { get { return ((FeatureTreeGroupRelationship)this.Parent).ParentNode; } }

        public FeatureTreeObjectExtension ObjectExtension { get { return _objExtension; } }

        public FMRectangle Shape
        {
            get { return _rectangle; }
            set
            {
                _rectangle = value;
            }
        }
        #endregion

        #region Fields
        private string _featureName;
        private string _annotation;

        private bool _existError;
        private FMSet<ErrorType> _errorMessage;
        private bool _existWarning;
        private FMSet<WarningType> _warningMessage;

        // feature model graphical fields
        private FMRectangle _rectangle;
        private FeatureTreeObjectExtension _objExtension;
        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="id"></param>
        public FeatureTreeNode(TreeNodeIdentify id, String featureName)
            : base(id)
        {
            _featureName = featureName;
            _annotation = string.Empty;

            _objExtension = new FeatureTreeObjectExtension(this);

            _rectangle = new FMRectangle();
            _rectangle.Width = _DEFAULT_WIDTH;
            _rectangle.Height = _DEFAULT_HEIGHT;

            _existWarning = false;
            _existError = false;
            _errorMessage = new FMSet<ErrorType>();
            _warningMessage = new FMSet<WarningType>();
        }
        #endregion
        /// <summary>
        /// construct Tree Node
        /// </summary>
        /// <param name="id"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static FeatureTreeNode ConstructTreeNode(TreeNodeIdentify id, object[] args)
        {
            if (args == null
                || args.Length != 1
                || !(args[0] is String))
            {
                return new FeatureTreeNode(id, string.Empty);
            }
            return new FeatureTreeNode(id, (string)args[0]);
        }

        #region Xml Parser
        /// <summary>
        /// To Xelement
        /// </summary>
        /// <returns></returns>
        public override XElement ToXElem()
        {
            XElement xelem = base.ToXElem();
            xelem.Add(new XAttribute(_XML_NODE_NAME, _featureName));
            xelem.Add(new XAttribute(_XML_ANNOTATION, _annotation));

            _rectangle.ToXElem(xelem);
            return xelem;
        }
        /// <summary>
        /// Xml Parser
        /// </summary>
        /// <param name="xelem"></param>
        /// <returns></returns>
        public static void xmlParser(XElement xelem, TreeObject obj)
        {
            FeatureTreeNode newNode = obj as FeatureTreeNode;
            if (newNode == null)
            {
                throw new Exception("Type Error!");
            }
            
            string nodeName = xelem.Attribute(_XML_NODE_NAME).Value;
            string annotation = xelem.Attribute(_XML_ANNOTATION).Value;

            newNode._featureName = nodeName;
            newNode._annotation = annotation;

            newNode._rectangle = FMRectangle.ParseXElem(xelem);
        }
        #endregion

        /// <summary>
        /// To String
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.FeatureName;
        }

        #region Get Tree hierarchy Objects
        /// <summary>
        /// Get Properties
        /// </summary>
        /// <returns></returns>
        private FeatureNodeProperty[] allProperties()
        {
            List<FeatureNodeProperty> properties = new List<FeatureNodeProperty>();
            foreach (INonRoot child in this.Children)
            {
                if (child is FeatureNodeProperty)
                {
                    properties.Add((FeatureNodeProperty)child);
                }
            }
            return properties.ToArray<FeatureNodeProperty>();
        }
        /// <summary>
        /// Get all children nodes
        /// </summary>
        /// <returns></returns>
        private IFeature[] childrenNodes()
        {
            List<IFeature> nodes = new List<IFeature>();
            foreach (FeatureTreeGroupRelationship gR in this.ChildrenGroupRelationshipes)
            {
                nodes.AddRange(gR.ChildrenNodes);
            }
            return nodes.ToArray<IFeature>();
        }
        /// <summary>
        /// Get all children group relationship
        /// </summary>
        /// <returns></returns>
        private FeatureTreeGroupRelationship[] childrenGroupRelationship()
        {
            List<FeatureTreeGroupRelationship> gRelationships 
                = new List<FeatureTreeGroupRelationship>();
            foreach (INonRoot child in this.Children)
            {
                if (child is FeatureTreeGroupRelationship)
                {
                    gRelationships.Add((FeatureTreeGroupRelationship)child);
                }
            }
            return gRelationships.ToArray<FeatureTreeGroupRelationship>();
        }
        #endregion

        #region Error & Message
        /// <summary>
        /// Exist Error
        /// </summary>
        public bool ExistError { get { return _existError; } }
        /// <summary>
        /// Error Message
        /// </summary>
        public ErrorType[] ErrorMessages { get { return _errorMessage.ToArray<ErrorType>(); } }
        /// <summary>
        /// Clear Error all Message
        /// </summary>
        public void ClearErrorMessages()
        {
            this._errorMessage.Clear();
            this._existError = false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="msg"></param>
        public void AddErrorMessage(ErrorType msg)
        {
            this._errorMessage.Add(msg);
            this._existError = true;
        }
        /// <summary>
        /// Exist Warning
        /// </summary>
        public bool ExistWarning { get { return _existWarning; } }
        /// <summary>
        /// Clear All Warning Messages
        /// </summary>
        public void ClearWarningMessages()
        {
            this._warningMessage.Clear();
            this._existWarning = false;
        }
        /// <summary>
        /// Add warning msg
        /// </summary>
        /// <param name="msg"></param>
        public void AddWarningMessage(WarningType msg)
        {
            this._warningMessage.Add(msg);
            this._existWarning = true;
        }
        /// <summary>
        /// Warning Messages
        /// </summary>
        public WarningType[] WarningMessages { get { return _warningMessage.ToArray<WarningType>(); } }
        #endregion




        /// <summary>
        /// Parse node to root
        /// </summary>
        /// <returns></returns>
        public override TreeRoot Parse2TreeRoot()
        {
            FeatureTreeRoot root = new FeatureTreeRoot(this.ID);
            root.FeatureName = this.FeatureName;
            root.Annotation = this.Annotation;
            return root;
        }

        /// <summary>
        /// Clone the value feilds and tree node link information.
        /// Not clone the cross tree constraint information.
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            FeatureTreeNode ret = new FeatureTreeNode(this.ID, this._featureName);
            ret._annotation = this._annotation;

            foreach (INonRoot child in this.Children)
            {
                INonRoot newChild = (INonRoot)child.Clone();
                if (newChild == null)
                {
                    continue;
                }
                ret.AddChild(newChild);
            }

            return ret;
        }
    }
}
